package models;

import jodd.bean.BeanCopy;
import models.admin.AdminUser;
import models.constants.AvailableStatus;
import models.constants.DeletedStatus;
import models.system.Company;
import org.hibernate.SQLQuery;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.transform.Transformers;
import play.db.jpa.GenericModel;
import play.db.jpa.JPA;
import play.db.jpa.JPABase;
import util.common.ClassUtil;
import util.common.ConvertUtil;
import util.common.DateUtil;

import javax.persistence.*;
import java.util.Date;
import java.util.List;
import java.util.Map;

@MappedSuperclass
public class UUIDModel extends GenericModel {

    @Id
    @GeneratedValue(generator = "IdGenerator")
    @GenericGenerator(name = "IdGenerator", strategy = "models.uuid.RandomUUIDGenerator")
    @Column(columnDefinition = "char(32)")
    public String id = "";

    public String getId() {
        return id;
    }

    @Override
    public Object _key() {
        return getId();
    }

    /**
     * 保存方法
     *
     * @param <T>
     */
    public <T extends BaseModel> void update() {
        List eList = em().createQuery("select e from " + this.getClass().getName() + " e where e.id=" + this.id.toString()).getResultList();
        if (eList != null && eList.size() > 0) {
            T target = (T) eList.get(0);
            BeanCopy.beans(this, target).ignoreNulls(true).copy();
            target.save();
        }
    }

    public final static String SQL_CODE_SELECT = "select version,code_num,code_date,prefix,code_date_available from admin_business where main_entity = ?";
    public final static String SQL_CODE_UPDDATE = "update admin_business set code_num = ?,code_date=?,version=version+1 where main_entity = ? and version = ?";

    /**
     * 加载code
     */
    public void loadKey() {
        ClassUtil.setFiledValue(this, "code", loadCode(false));
    }

    /**
     * 使用乐观锁解决集群下分布式服务生成流水号重复问题
     *
     * @param isError
     * @return
     */
    private String loadCode(boolean isError) {
        String entityName = this.getClass().getSimpleName();
        Query query = null;
        if (isError)
            query = JPA.newEntityManager().createNativeQuery(SQL_CODE_SELECT).setParameter(1, entityName);
        else
            query = em().createNativeQuery(SQL_CODE_SELECT).setParameter(1, entityName);
        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map<String, Object>> businessList = query.getResultList();

        if (businessList == null || businessList.size() == 0)
            return "";

        Map<String, Object> adminBuisness = businessList.get(0);
        Integer version = ConvertUtil.toInteger(adminBuisness.get("version"));
        String prefix = ConvertUtil.toString(adminBuisness.get("prefix"));
        Integer codeNum = ConvertUtil.toInteger(adminBuisness.get("code_num"));
        String codeDateAvailable = ConvertUtil.toString(adminBuisness.get("code_date_available"));
        String orgDateStr = ConvertUtil.toString(adminBuisness.get("code_date"));
        String todayDataStr = "";

        if (codeDateAvailable.equals(AvailableStatus.AVAILABLE.toString())) {
            Date today = DateUtil.getBeginOfDay();
            todayDataStr = DateUtil.dateToString(today, "yyyyMMdd");

            if (!todayDataStr.equals(orgDateStr)) {
                codeNum = 0;
            }
        }

        Query updateQuery = em().createNativeQuery(SQL_CODE_UPDDATE)
                .setParameter(1, ++codeNum)
                .setParameter(2, todayDataStr)
                .setParameter(3, entityName)
                .setParameter(4, version);
        int updateQty = updateQuery.executeUpdate();
        if (updateQty > 0) {
            return prefix + todayDataStr + ConvertUtil.toString(10000 + codeNum).substring(1);
        } else {
            return loadCode(true);
        }

    }

    /**
     * 系统不允许删除.
     */
    @Override
    public <T extends JPABase> T delete() {
        return (T) this;
    }


    /**
     * 逻辑删除,0:未删除，1:已删除
     */
    @Enumerated(EnumType.ORDINAL)
    @Column(name = "deleted")
    public DeletedStatus deleted = DeletedStatus.UN_DELETED;


    //所属公司
    @ManyToOne
    @JoinColumn(name = "belong_company_id")
    public Company belongCompany;

    //创建人
    @ManyToOne
    @JoinColumn(name = "create_user_id")
    public AdminUser createUser;

    /**
     * 创建时间
     */
    @Column(name = "created_at")
    public Date createdAt;


    //最后修改人
    @ManyToOne
    @JoinColumn(name = "update_user_id")
    public AdminUser updateUser;

    /**
     * 最后修改时间
     */
    @Column(name = "updated_at")
    public Date updatedAt;
}
